<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>learn vue.js</title>
</head>

<!--每个示例div加边框分隔-->
<style>
    div {
        margin-bottom: 10px;
        border-color: #115a6268;
        border-width: 1px;
        border-style: dashed;
    }

    table tr:nth-child(2n) {
        background-color: #00ffff;
    }
</style>

<style>
    /*基于class的过渡和动画*/
    .shake {
        animation: shake 0.5s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
        transform: translate3d(0, 0, 0);
        backface-visibility: hidden;
        perspective: 1000px;
        /*
        让浏览器硬件加速使用以下任一一个就可以
        perspective: 1000px;
        backface-visibility: hidden;
        transform: translateZ(0);
        */
    }

    @keyframes shake {
        10%, 90% {
            transform: translate3d(-1px, 0, 0);
        }
        20%, 80% {
            transform: translate3d(2px, 0, 0);
        }
        30%, 50%, 70% {
            transform: translate3d(-4px, 0, 0);
        }
        40%, 60% {
            transform: translate3d(4px, 0, 0);
        }
    }

    /*过渡与style绑定*/
    .movearea {
        transition: 0.0s background-color ease;
    }

    /*easing button*/
    .easing-button {
        background: #1b8f5a;
        transition: background 0.25s ease-in;
        border-radius: 4px;
        display: inline-block;
        border: none;
        padding: 0.75rem 1rem;
        margin: 0;
        text-decoration: none;
        color: #ffffff;
        font-family: sans-serif;
        font-size: 1rem;
        cursor: pointer;
        text-align: center;
        -webkit-appearance: none;
        -moz-appearance: none;
    }

    .easing-button:hover,
    .easing-button:focus {
        transition: background 0.3s ease-out;
        background: #3eaf7c;
    }

    .easing-button:focus {
        outline: 1px solid #fff;
        outline-offset: -4px;
    }

    /*单元素/组件的过渡*/
    .fade-enter-active, .fade-leave-active {
        transition: opacity 0.5s ease;
    }

    .fade-enter-form, .fade-leave-to {
        opacity: 0;
    }
</style>

<body>

<!--PART A基础部分-->
<!--C1介绍-->
<!--将数据渲染进DOM-->
<div>
    <div id="counter">
        Counter: {{counter}}
        <span v-once>v-once->Counter: {{counter}}</span>
    </div>

    <!--绑定元素的attr值:v-bind指令-->
    <div id="bind-attribute">
    <span v-bind:title="message">
        悬停鼠标查看提示信息
    </span>
    </div>

    <!--处理用户输入:v-on事件监听器-->
    <div id="event-handling">
        {{message}}<br/>
        <button v-on:click="reverseMessage">反转message</button>
    </div>

    <!--处理用户输入:v-model双向绑定表单输入和应用状态-->
    <div id="two-way-binding">
        {{message}}<br/>
        <input v-model="message"/>
    </div>

    <!--条件v-if-->
    <div id="conditional-rendering">
        <button v-if="seen">是否能看见我</button>
    </div>

    <!--循环v-for-->
    <div id="list-rendering">
        <ol>
            <li v-for="todo in todos">
                {{todo.text}}
            </li>
        </ol>
    </div>

    <!-- 定义组件:todo对象是变量 -->
    <div id="todo-list-app">
        <ol>
            <todo-item v-for="item in groceryList" v-bind:todo="item" v-bind:key="item.id">
            </todo-item>
        </ol>
    </div>

    <!--C4data property和方法-->
    <div id="only-in-vue-js">
        <button @click="increment">add count:{{count}}</button>
    </div>

    <!--C5计算属性和侦听器-->
    <div id="computed-basics">
        <p>has published books:{{publishedBooksMessage}}|{{publishedBooksMessage}} @author's name:{{authorName}}</p>
    </div>

    <div id="watch-example">
        <p>ask a yes/no question:<input v-model="question"/>, answer:{{answer}}</p>
    </div>

    <!--C7条件渲染-->
    <div id="v-if-else">
        <!--v-if&v-else-->
        <i v-if="awesome">vue is awesome!</i>
        <i v-else>vue is not awesome!</i><br/>
        <!--template:不可见的包裹元素-->
        <template v-if="awesome">
            <i>vue is</i>
            <i>~~~awesome!</i>
        </template>
        <i v-else>vue is not awesome!(template)</i><br/>
        <!--v-else-if-->
        <i v-if="type === 'A'">show A</i>
        <i v-else-if="type === 'B'">show B</i>
        <i v-else>not A or B</i><br/>
        <!--v-show-->
        <i v-show="awesome" style="color: red">v-show's result</i>
    </div>

    <!--C8列表渲染-->
    <div id="c8-v-for">
        <ul>
            <!--<li v-for="item in items">-->
            <li v-for="(item,index) in items">
                index:{{index}}, title:{{title}}, message:{{item.message}}
            </li>
            <hr/>
            <!--:key维护状态?-->
            <li v-for="(value,key,index) in user" :key="key">
                index:{{index}}, key:{{key}}, value:{{value}}
            </li>
        </ul>
        <button @click="change">更新数据源</button>
    </div>

    <div id="todo-list-example">
        <form v-on:submit.prevent="addNewTodo">
            <label for="new-todo">add a todo</label>
            <input v-model="newTodoText" id="new-todo" placeholder="example:get up">
            <button>add</button>
        </form>
        <ul>
            <todo-item v-for="(todo,index) in todos" :key="todo.id"
                       :title="todo.title" @remove="todos.splice(index,1)"></todo-item>
        </ul>
    </div>

    <!--C9事件处理-->
    <div id="c9-v-on">
        <button @click="click('akali',$event),two(20)">click</button>
    </div>

    <!--C10表单输入绑定v-model-->
    <div id="c10-v-model">
        <input v-model="message" placeholder="edit input"/>message is:{{message}}<br/>
        <textarea v-model="messages" placeholder="edit textarea"></textarea><br/>
        <p style="white-space: pre-line">messages is:{{messages}}</p>
        <input type="checkbox" id="checkbox" v-model="checked"/>
        <label for="checkbox">{{checked}}</label>
    </div>
</div>

<hr style="border: #0c5460 solid 10px" title="ss"/>
<!--PART B动画部分-->
<!--过渡&动画概述-->
<div id="anim-trans-class">
    <!--基于class的过渡和动画-->
    <div :class="{shake:noActivated}">
        <h6>try click inefficient button</h6>
        <button @click="noActivated=true">click me</button>
        <span v-if="noActivated">on no!</span>
    </div>
    <!--过渡与style绑定-->
    <div @mousemove="xCoordinate" :style="{backgroundColor:`hsl(${x},80%,50%)`}" class="movearea">
        <h6>move your mouse across the screen...</h6>x:{{x}}
    </div>
    <!--easing button-->
    <button class="easing-button">hover me!</button>
</div>

<!--进入过渡&离开过渡-->
<div id="anim-in-out">
    <!--单元素/组件的过渡-->
    <button @click="show=!show">toggle button</button>
    <transition name="fade">
        <p v-if="show">hello</p>
    </transition>
</div>

<!---->
<!--table-->
<table id="winning-table">
    <thead>
    <tr>
        <th align="left">id</th>
        <th align="left">name</th>
        <th align="left">address</th>
    </tr>
    </thead>
    <tbody>
    <tr v-for="o in items">
        <td v-text="o.id"></td>
        <td v-text="o.name"></td>
        <td v-text="o.address"></td>
    </tr>
    </tbody>
</table>


<!--------------------------------------------=-->
<!-- v3.1.4 -->
<script src="https://unpkg.com/vue@next"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script>
    Vue.createApp({
        data() {
            return {
                items: [
                    {'id': '1', 'name': 'zhangsan', 'address': 'china'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1134534534534511', 'address': 'china1113454353451'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {
                        'id': '2',
                        'name': 'zhangsan1111',
                        'address': 'china111sgergregergergegrgeegegegrgeg1china111sgergregergergegrgeegegegrgeg1china111sgergregergergegrgeegegegrgeg1china111sgergregergergegrgeegegegrgeg1china111sgergregergergegrgeegegegrgeg1china111sgergrergerg'
                    },
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                    {'id': '2', 'name': 'zhangsan1111', 'address': 'china1111'},
                ]
            }
        },
        methods: {
            getData(datas) {
                this.items = datas;
                return "items:" + JSON.stringify(this.items);
            }
        },
        mounted() {
            window.getData = datas => this.getData(datas);
        },
    }).mount('#winning-table')//和Java交互

    Vue.createApp({
        data() {
            return {
                show: true
            }
        },
        methods: {}
    }).mount('#anim-in-out')
    //C2进入过渡&离开过渡

    Vue.createApp({
        data() {
            return {
                noActivated: false,//基于class的过渡和动画
                x: 0
            }
        },
        methods: {
            xCoordinate(e) {//过渡与style绑定
                this.x = e.clientX
            }
        }
    }).mount('#anim-trans-class')
    //C1过渡&动画概述
</script>
<script>
    //基础
    Vue.createApp({
        data() {
            return {
                message: '',
                messages: '',
                checked: false
            }
        }
    }).mount('#c10-v-model')
    //C10表单输入绑定v-model

    /*
    事件修饰符
    */
    Vue.createApp({
        data() {
            return {}
        },
        methods: {
            click(name, event) {//v-on中传入$event可在js中访问原始的dom事件
                alert('name:' + name)
                alert('event:' + event.target.tagName)
            },
            two(age) {//多事件处理
                alert('age is:' + age)
            }
        }
    }).mount('#c9-v-on')
    //C9事件处理//

    const todoListExampleApp = Vue.createApp({
        data() {
            return {
                newTodoText: '',
                todos: [
                    {id: 1, title: 'get up'}, {id: 2, title: 'wash face'}
                ], nextTodoId: 3
            }
        },
        methods: {
            addNewTodo() {
                this.todos.push({
                    id: this.nextTodoId++, title: this.newTodoText
                })
                this.newTodoText = ''
            }
        }
    })
    todoListExampleApp.component('todo-item', {
        template: `
            <li>
                {{title}}
                <button @click="$emit('remove')">remove</button>
            </li>
        `,
        props: ['title'],
        emits: ['remove']
    })
    todoListExampleApp.mount('#todo-list-example')
    Vue.createApp({
        data() {
            return {
                title: 'show items',//v-for块可访问父作用域的property
                items: [
                    {message: 'foo'},
                    {message: 'bar'}
                ],
                user: {//v-for遍历对象的property
                    name: 'akali',
                    age: 20,
                    country: '均衡教派'
                }
            }
        },
        methods: {
            change() {
                console.log('更新数据源')
                this.user = {
                    age: 22,
                    country: '弗雷尔卓德',
                    name: 'ashe'
                }
                //变更方法push()|pop()|shift()|unshift()|splice()|sort()|reverse()
                this.items.push({message: 'header'})
                //替换数组filter()|concat()|slice()返回新数组
                //组件上使用v-for=>template同v-if一样使用
            }
        }
    }).mount('#c8-v-for')
    //C8列表渲染//

    Vue.createApp({
        data() {
            return {
                awesome: true,
                type: 'B'
            }
        }
    }).mount('#v-if-else')
    /*
    1.v-if、v-if ... v-else-if ... v-else、v-show
    2.v-if:初始渲染条件为假时什么也不做，直到条件为真才真正开始进行渲染
    3.v-show不管初始条件总会渲染元素，只是简单的进行display切换
    2.&3.=>频繁切换渲染条件使用v-show性能更好
    */
    //C7条件渲染//

    /*
    A.绑定class
    1.:class="{active:isActive}":表示active这个class存在与否取决于isActive的truth
    2.:class="{active:isActive, 'text-danger':hasError}":多个控制的class
    3.data()中绑定class
    <div :class="classObject"></div>
    data() {
        return {
            classObject: {
                active: true,
                'text-danger': false
            }
        }
    }
    4.使用计算属性
    data() {
        return {
            isActive: true,
            error: null
        }
    },
    computed: {
        classObject() {
            return {
                active: this.isActive && !this.error,
                'text-danger': this.error && this.error.type === 'fatal'
            }
        }
    }
    4.将数组传给:class
    <div :class="[activeClass, errorClass]"></div>
    data() {
        return {
            activeClass: 'active',
            errorClass: 'text-danger'
        }
    }
    5.根据条件切换class
    <div :class="[isActive ? activeClass : '', errorClass]"></div>
    =>简写
    <div :class="[{activeClass: isActive}, errorClass]"></div>
    B.绑定style内联样式
    1.给控件绑定样式
    <div :style="{color: activeColor, fontSize: fontSize + 'px'}"></div>
    data() {
        return {
            activeColor: 'red',
            fontSize: 30
        }
    }
    2.给控件绑定样式对象
    <div :style="styleObject"></div>
    data() {
        return {
            styleObject: {
                color: 'red',
                fontSize: '30px'
            }
        }
    }
    3.通过数组给控件绑定多个样式对象
    <div :style="[baseStyles, overridingStyles]"></div>
    */
    //C6class与style绑定//

    //侦听器watch适用于数据变化时执行异步活开销较大的操作
    Vue.createApp({
        data() {
            return {
                question: '',
                answer: 'Questions usually contain a question mark. ;-)'
            }
        },
        watch: {
            question(newQuestion, oldQuestion) {
                if (newQuestion.indexOf('?') > -1) {
                    this.getAnswer()
                }
            }
        },
        methods: {
            getAnswer() {
                this.answer = 'Thinking...'
                axios
                    .get('https://yesno.wtf/api')
                    .then(response => {
                        this.answer = response.data.answer
                    })
                    .catch(error => {
                        this.answer = 'Error! Could not reach the API. ' + error
                    })
            }
        }
    }).mount('#watch-example')
    //计算属性computed
    Vue.createApp({
        data() {
            return {
                author: {
                    name: 'akali',
                    books: [
                        'book1-food',
                        'book2-game'
                    ]
                }
            }
        },
        computed: {
            publishedBooksMessage() {//计算属性publishedBooksMessage
                return this.author.books.length > 0 ? 'yes' : 'no'
            },
            authorName: {//计算属性authorName
                //计算属性默认只有getter当然可以像下面一样提供setter
                //当调用vm.authorName = 'xx'时setter方法会被调用
                get() {
                    return this.author.name
                },
                set(value) {
                    //...
                }
            }
        },
        methods: {
            //通过调用methods方法也能达到同样效果，但计算属性有缓存功能只在相关响应式依赖发生改变时才会重新求值所以效率更高
            publishedBooksMessageByMethod() {
                return this.author.books.length > 0 ? 'yes' : 'no'
            }
        }
    }).mount('#computed-basics')
    //C5计算属性和侦听器//

    /*
    1.防抖使用lodash:https://unpkg.com/lodash@4.17.20/lodash.min.js
    */
    //Vue使用$前缀通过组件实例暴露内置的api
    const OnlyInVueJs = {
        data() {//data函数返回对象并以$data的形式存储在组件实例中
            return {
                count: 4
            }
        },
        methods: {
            increment() {
                this.count++//this指向该组件实例
            }
        }
    }
    const onlyInVueJs = Vue.createApp(OnlyInVueJs)
    const vm = onlyInVueJs.mount('#only-in-vue-js')
    console.log('vm.$data.count:' + vm.$data.count)
    console.log('vm.count:' + vm.count)
    //修改其中一个会影响另一个的值
    vm.count = 5
    console.log('vm.$data.count:' + vm.$data.count)
    vm.$data.count = 6
    console.log('vm.count:' + vm.count)
    vm.increment()
    console.log('after increment()->vm.$data.count:' + vm.$data.count)
    console.log('after increment()->vm.count:' + vm.count)
    //C4data property和方法//

    /*
    1.v-once[标签中]:只能一次插值，当数据改变时内容不会更新
    2.v-html[内容中]:输出原样html
    3.v-bind:disabled[标签中]:使得js中可使用Vue(mustache)语法
    4.模板中使用js表达式[只能是单个表达式]:{{num+1}}、{{ok?'1':'0'}}、{{msg.split('').reverse().join('')}}等
    5.指令:v-[标签中|v-for&v-on是例外]:v-if="seen"
    6.带参数的指令[标签中]:v-bind:href="url"、v-on:click="doSomething"
    7.动态参数:v-bind:[attr-name]、v-on:[event-name]
    8.缩写(完整=>缩写=>动态参数缩写):v-bind:href="url"=>:href="url"=>:[key]="url"、v-on:click="do"=>@click="do"=>@[event]="do"
    */
    //C3模板语法//

    /*
    1.const app = Vue.createApp({})函数创建实例
    2.挂载应用至某组件(id='app'):app.mount('#app')
    3.组件实例property:methods、props、computed、inject、setup等
    4.生命周期:data(){},created(){}中的created以及mounted、updated、unmounted等
    */
    //C2应用&组件实例//

    /*<!-- 定义组件 -->*/
    const TodoList = {
        data() {
            return {
                groceryList: [
                    {id: 0, text: 'vegetables'},
                    {id: 1, text: 'cheese'},
                    {id: 2, text: 'others'}
                ]
            }
        }
    }
    const todoListApp = Vue.createApp(TodoList)
    todoListApp.component('todo-item', {
        props: ['todo'],
        template: `<li>{{todo.text}}</li>`
    })
    todoListApp.mount('#todo-list-app')

    /*循环v-for*/
    const ListRendering = {
        data() {
            return {
                todos: [
                    {text: 'first'},
                    {text: 'second'},
                    {text: 'third'}
                ]
            }
        }
    }
    Vue.createApp(ListRendering).mount('#list-rendering')

    /*条件v-if*/
    const ConditionalRendering = {
        data() {
            return {
                seen: true
            }
        }
    }
    Vue.createApp(ConditionalRendering).mount('#conditional-rendering')

    /*处理用户输入:v-model双向绑定表单输入和应用状态*/
    const TwoWayBinding = {
        data() {
            return {
                message: 'hello world!'
            }
        }
    }
    Vue.createApp(TwoWayBinding).mount('#two-way-binding')

    /*处理用户输入:v-on事件监听器*/
    const EventHandling = {
        data() {
            return {
                message: 'hello  world!'
            }
        }, methods: {
            reverseMessage() {
                this.message = this.message.split('').reverse().join('')
            }
        }
    }
    Vue.createApp(EventHandling).mount('#event-handling')

    /*绑定元素的attr值*/
    const AttributeBinding = {
        data() {
            return {
                message: '当前时间:' + new Date().toLocaleString()
            }
        }
    }
    Vue.createApp(AttributeBinding).mount('#bind-attribute')

    /*将数据渲染进DOM*/
    const Counter = {
        data() {
            return {
                counter: 0
            }
        }, mounted() {
            let interval = setInterval(() => {
                this.counter++
                if (5 === this.counter) {
                    clearInterval(interval)
                }
            }, 1000)
        }
    }
    Vue.createApp(Counter).mount('#counter')
    //C1介绍//
</script>
</body>
</html>